/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.example.frame.starters.base.init;

import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * ApplicationContentPostProcessor 是一个用于确保 Spring Boot 应用启动完成后仅执行一次初始化逻辑的组件。
 *
 * 通过监听 Spring Boot 的 ApplicationReadyEvent 事件，
 * 在应用完全启动后触发 自定义初始化逻辑 ，并确保该逻辑仅执行一次
 */

//该类实现了 ApplicationListener<ApplicationReadyEvent> 接口，
// 当 Spring Boot 完成所有 Bean 初始化并启动成功后，ApplicationReadyEvent 事件会被自动触发
@RequiredArgsConstructor
public class ApplicationContentPostProcessor implements ApplicationListener<ApplicationReadyEvent> {

    private final ApplicationContext applicationContext;

    /**
     * 执行标识，确保Spring事件 {@link ApplicationReadyEvent} 有且执行一次
     */
    private final AtomicBoolean executeOnlyOnce = new AtomicBoolean(false);

    //ApplicationReadyEvent触发后，执行该方法
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        //通过 AtomicBoolean 检查是否为首次执行。若否，直接返回
        if (!executeOnlyOnce.compareAndSet(false, true)) {
            return;
        }
        //applicationContext.publishEvent() 是 Spring 框架中 事件驱动模型的核心方法，
        // 其作用是通过发布（触发）一个事件，通知所有监听该事件的组件执行特定逻辑，比如后面设计模式那个模块会监听ApplicationInitializingEvent
        applicationContext.publishEvent(new ApplicationInitializingEvent(this));
    }
}

/*这段代码实现了 应用启动完成后的安全初始化控制：

严格单次执行：通过 CAS 原子操作避免重复初始化
分层初始化设计：将初始化动作拆解为可订阅的独立事件
线程安全保障：应对 Spring 事件可能存在的并发场景
架构扩展性：为后续添加多种初始化逻辑提供统一入口
*
* */
